home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / UUPC11QS.ARJ / RMAIL.C < prev    next >
C/C++ Source or Header  |  1991-12-07  |  36KB  |  871 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    Program:    rmail.c        16 September 1990                    */
  3. /*    Author:     Andrew H. Derbyshire                                */
  4. /*                108 Decatur Street, Apt 9                           */
  5. /*                Arlington, MA 02174                                 */
  6. /*    Internet:   help@kendra.kew.com                                 */
  7. /*    Function:   Stand alone mail delivery module for                */
  8. /*                UUPC/extended                                       */
  9. /*    Language:   Borland C++ 2.0 (ANSI C mode) or Microsoft C 6.0.   */
  10. /*    Arguments:  One or more addresses to deliver mail to            */
  11. /*                or "-t" to direct rmail to read the addresses       */
  12. /*                from the RFC-822 header.                            */
  13. /*                A third mode of operation is to specify '-w' and/   */
  14. /*                or '-s subject' followed by one or more addresses   */
  15. /*                with optional carbon copy flags (-c or -b) before   */
  16. /*                additional addresses.  This causes rmail to         */
  17. /*                function like a bare bones batch version of the     */
  18. /*                MAIL program; a valid RFC-822 header is generated   */
  19. /*                and the mail is delivered, aliases are not expanded */
  20. /*                and the mail is not locally logged.  (The current   */
  21. /*                user id as the from address is used unless the      */
  22. /*                environment variable LOGNAME is set, in which case  */
  23. /*                it is used.)                                        */
  24. /*                Optional argument "-f" to denote file to read in    */
  25. /*                place of stdin.                                     */
  26. /*                Optional argument "-F" to denote file to read in    */
  27. /*                place of stdin and DELETE after readering.          */
  28. /*                Optional argument "-x" to for debug level           */
  29. /*    Input:      mail to be delivered, with RFC-822 header, on       */
  30. /*                stdin.                                              */
  31. /*    Output:     'From' and 'Received:' headers are added,           */
  32. /*                'Bcc:' headers are removed, and the mail is         */
  33. /*                delivered to one or more local users and/or         */
  34. /*                one or more remote users.                           */
  35. /*    Exit code:  0  Success                                          */
  36. /*                1  One or more letters not delivered                */
  37. /*                2  No mail delivered                                */
  38. /*                3 Configuration file error                          */
  39. /*                4 Invalid option/help specified                     */
  40. /*                5 Invalid option/help specified                     */
  41. /*                                                                    */
  42. /*    Note:       When parsing RFC-822 headers, this program          */
  43. /*                expects them to be "well-behaved", that is in       */
  44. /*                format generated by UUPC/extended.  This implies:   */
  45. /*                                                                    */
  46. /*                      One address per line                          */
  47. /*                                                                    */
  48. /*                      Resent- headers, if any, before the original  */
  49. /*                      headers.                                      */
  50. /*                                                                    */
  51. /*                      From: header must precede To: header.         */
  52. /*                                                                    */
  53. /*                      To: header must precede Cc: and Bcc: headers. */
  54. /*                                                                    */
  55. /*                      Cc: and Bcc: headers must be together (one    */
  56. /*                      after the other)                              */
  57. /*                                                                    */
  58. /*                      The MUA has prefixed any obsolete Resent-     */
  59. /*                      headers by X-                                 */
  60. /*                                                                    */
  61. /*    Note:       The "-t" flag is supported by BSD sendmail for the  */
  62. /*                purpose listed above, but we also turn use it to    */
  63. /*                control other special options, all of which         */
  64. /*                basically cause the program to act more like a      */
  65. /*                local mailer than a remote mailer; these options    */
  66. /*                include:                                            */
  67. /*                                                                    */
  68. /*                      Stripping off blind carbon copies             */
  69. /*                                                                    */
  70. /*                      Generating the UUCP From line differently     */
  71. /*--------------------------------------------------------------------*/
  72.  
  73. /*--------------------------------------------------------------------*/
  74. /*                        System include files                        */
  75. /*--------------------------------------------------------------------*/
  76.  
  77. #include <stdio.h>
  78. #include <ctype.h>
  79. #include <io.h>
  80. #include <stdlib.h>
  81. #include <string.h>
  82. #include <time.h>
  83.  
  84. /*--------------------------------------------------------------------*/
  85. /*                     Application include files                      */
  86. /*--------------------------------------------------------------------*/
  87.  
  88. #include "lib.h"
  89. #include "address.h"
  90. #include "arpadate.h"
  91. #include "deliver.h"
  92. #include "getopt.h"
  93. #include "hlib.h"
  94. #include "hostable.h"
  95. #include "security.h"
  96. #include "usertabl.h"
  97. #include "timestmp.h"
  98.  
  99. /*--------------------------------------------------------------------*/
  100. /*                           Local defines                            */
  101. /*--------------------------------------------------------------------*/
  102.  
  103. #define  MOPLEN      10          /* Length of formatted header lines */
  104. #define  UUCPFROM    "From "     /* Length of UUCP incoming mail     */
  105.  
  106. /*--------------------------------------------------------------------*/
  107. /*                   Prototypes for internal files                    */
  108. /*--------------------------------------------------------------------*/
  109.  
  110. static boolean CopyTemp( void );
  111.  
  112. static void ParseFrom( void );
  113.  
  114. static char **Parse822( boolean *header,
  115.                         size_t *count);
  116.  
  117. static void Terminate( const int rc);
  118.  
  119.  static void PutHead( const char *label,
  120.                       const char *operand,
  121.                       FILE *stream,
  122.                       const boolean resent);
  123.  
  124. static boolean DaemonMail( const char *subject,
  125.                            char **address,
  126.                            int count );
  127.  
  128. /*--------------------------------------------------------------------*/
  129. /*                          Global variables                          */
  130. /*--------------------------------------------------------------------*/
  131.  
  132.  currentfile();               /* Declare file name for checkref()    */
  133.  char *tempname = NULL;       /* Pointer to temporary input file     */
  134.  char *namein = CONSOLE;
  135.  FILE *datain = stdin;        /* Handle for reading input mail       */
  136.  FILE *dataout = NULL;        /* Handle for the output of mail       */
  137.  char fromuser[MAXADDR] = ""; /* User id of originator               */
  138.  char fromnode[MAXADDR] = ""; /* Node id of originator               */
  139.  char *now;                   /* Time stamp for Received: banner     */
  140.  
  141.  static char received[] = "Received:";
  142.  static char receivedlen = sizeof( received) - 1;
  143.  
  144. /*--------------------------------------------------------------------*/
  145. /*                            main program                            */
  146. /*--------------------------------------------------------------------*/
  147.  
  148. void main(int argc, char **argv)
  149. {
  150.    boolean ReadHeader = FALSE;   /* TRUE = Parse RFC-822 headers      */
  151.  
  152.    int  option;                  /* For parsing option list           */
  153.    char logname[FILENAME_MAX];   /* Full name of log file             */
  154.    char **address;               /* Pointer to list of target
  155.                                     addresses                         */
  156.    char *token;
  157.    size_t addressees;            /* Number of targets in address      */
  158.    int    count;                 /* Loop variable for delivery        */
  159.    size_t delivered = 0;         /* Count of successfull deliveries   */
  160.    boolean header = TRUE;
  161.    boolean DeleteInput = FALSE;
  162.  
  163.    boolean daemon = FALSE;
  164.  
  165.    char *subject = NULL;
  166.  
  167. /*--------------------------------------------------------------------*/
  168. /*    Make a copy of the Borland copyright for debugging purposes     */
  169. /*--------------------------------------------------------------------*/
  170.  
  171. #if defined(__CORE__)
  172.    copywrong = strdup(copyright);
  173.    checkref(copywrong);
  174. #endif
  175.  
  176.    now = arpadate();          /* Set the current date                */
  177.    debuglevel = -1;           /* Set default so we can detect it     */
  178.    logecho = TRUE;            /* Display messages on console         */
  179.  
  180. /*--------------------------------------------------------------------*/
  181. /* Load the UUPC/extended configuration file, and exit if any errors  */
  182. /*--------------------------------------------------------------------*/
  183.  
  184.    if (!configure(B_MTA))
  185.       Terminate(3);
  186.  
  187. /*--------------------------------------------------------------------*/
  188. /*                       Begin logging messages                       */
  189. /*--------------------------------------------------------------------*/
  190.  
  191.    mkfilename(logname, spooldir, RMAILLOG);
  192.    if ((logfile = FOPEN(logname, "a", TEXT)) == nil(FILE))
  193.    {
  194.       fprintf(stderr,"%s: Cannot open %s, program terminating\n",
  195.                argv[0], logname);
  196.       Terminate( 3 );
  197.    } /* if */
  198.  
  199. /*--------------------------------------------------------------------*/
  200. /*                      Parse our operand flags                       */
  201. /*--------------------------------------------------------------------*/
  202.  
  203.    while ((option = getopt(argc, argv, "ws:a:tf:x:")) != EOF)
  204.    {
  205.       switch (option) {
  206.       case 'w':
  207.          daemon = TRUE;
  208.          break;
  209.  
  210.       case 's':
  211.          subject = optarg;
  212.          daemon = TRUE;
  213.          break;
  214.  
  215.       case 't':
  216.          ReadHeader = TRUE;
  217.          break;
  218.  
  219.       case 'x':
  220.          debuglevel = atoi(optarg);
  221.          break;
  222.  
  223.       case 'F':
  224.          DeleteInput = TRUE;
  225.       case 'f':
  226.          namein = optarg;
  227.          datain = FOPEN(namein , "r", TEXT);
  228.          break;
  229.  
  230.       case '?':
  231.          puts("\nUsage:\trmail  -t");
  232.          puts("\trmail [-x debug] addr1 addr2 addr3 ...");
  233.          Terminate(4);
  234.       } /* switch */
  235.    } /* while */
  236.  
  237.    if ( debuglevel > 1 )
  238.    {
  239.       for ( count = 1; count < argc; count ++)
  240.          printmsg(4,"rmail argv[%d] = \"%s\"", count, argv[count] );
  241.    } /* if ( debuglevel > 4 ) */
  242.  
  243.    if ((optind == argc) != ReadHeader)
  244.    {
  245.       puts("Missing/extra parameter(s) at end.");
  246.       Terminate(4);
  247.    }
  248.  
  249.    remoteMail = ! (ReadHeader || daemon);
  250.                               /* If not reading headers, must be in
  251.                                  normal rmail mode ...               */
  252.  
  253. /*--------------------------------------------------------------------*/
  254. /*    If in local mode and the user doesn't want output, suppress     */
  255. /*    routine delivery messages                                       */
  256. /*--------------------------------------------------------------------*/
  257.  
  258.    if ( debuglevel == -1 )
  259.    {
  260.       if (remoteMail)
  261.          debuglevel = 1;
  262.       else
  263.          debuglevel = (int) bflag[F_VERBOSE];
  264.    }
  265.  
  266. /*--------------------------------------------------------------------*/
  267. /*               Verify we have input stream available                */
  268. /*--------------------------------------------------------------------*/
  269.  
  270.    if (datain == NULL )
  271.    {
  272.       printerr(namein);
  273.       Terminate(3);
  274.    } /* if */
  275.  
  276. /*--------------------------------------------------------------------*/
  277. /*                   Open up the output data stream                   */
  278. /*--------------------------------------------------------------------*/
  279.  
  280.    tempname = mktempname( NULL , "TMP");
  281.    dataout = FOPEN(tempname, "w", TEXT);
  282.  
  283.    if (dataout == NULL)
  284.    {
  285.       printmsg(0,"Cannot open temporary file \"%s\" for output",
  286.             tempname);
  287.       Terminate(5);
  288.    } /* if */
  289.  
  290. /*--------------------------------------------------------------------*/
  291. /*   If in local mail mode, make up a list of addresses to mail to    */
  292. /*--------------------------------------------------------------------*/
  293.  
  294.    if ( daemon )
  295.    {
  296.       addressees = argc - optind;
  297.       address = &argv[optind];
  298.       DaemonMail( subject, address, addressees );
  299.       header = FALSE;
  300.    }
  301.    else if (ReadHeader)
  302.       address = Parse822( &header, &addressees );
  303.    else {
  304.       ParseFrom();               /* Copy remote header instead       */
  305.       addressees = argc - optind;
  306.       address = &argv[optind];
  307.    } /* if */
  308.  
  309.    if ( addressees == 0 )        /* Can we deliver mail?             */
  310.    {
  311.       printmsg(0, "No addressees to deliver to!");
  312.       Terminate( 2 );            /* No --> Execute punt formation    */
  313.    }
  314.  
  315. /*--------------------------------------------------------------------*/
  316. /*       Copy the rest of the input file into our holding tank        */
  317. /*--------------------------------------------------------------------*/
  318.  
  319.    header = CopyTemp( ) && header ;
  320.    if (header)                   /* Was the header ever terminated?  */
  321.    {
  322.       printmsg(0,"rmail: Improper header, adding trailing newline");
  323.       fputc('\n', dataout);      /* If not, it is now ...            */
  324.    }
  325.  
  326.    fclose(datain);
  327.    fclose(dataout);
  328.  
  329.    if (DeleteInput)              /* Make room for more data on disk  */
  330.       remove(namein);
  331.  
  332. /*--------------------------------------------------------------------*/
  333. /*                    Perform delivery of the mail                    */
  334. /*--------------------------------------------------------------------*/
  335.  
  336.    while ((token = strpbrk(tempname ,"/")) != NULL)
  337.       *token = '\\';
  338.  
  339.    for ( count = 0; count < addressees; count++)
  340.          if ( *address[count] == '-')
  341.             delivered ++;     /* Ignore option flags on delivery     */
  342.          else
  343.             delivered += Deliver(tempname, address[count], TRUE);
  344.  
  345. /*--------------------------------------------------------------------*/
  346. /*                       Terminate the program                        */
  347. /*--------------------------------------------------------------------*/
  348.  
  349.    printmsg(8,"rmail: %d addressees, delivered to %d mailboxes",
  350.             addressees, delivered);
  351.  
  352.    if ( delivered >= addressees )
  353.       Terminate( 0 );         /* All mail delivered                  */
  354.    else if ( delivered == 0 )
  355.       Terminate( 2 );         /* No mail delivered                   */
  356.    else
  357.       Terminate (1 );         /* Some mail delivered                 */
  358.  
  359. } /* main */
  360.  
  361. /*--------------------------------------------------------------------*/
  362. /*    T e r m i n a t e                                               */
  363. /*                                                                    */
  364. /*    Cleanup open files and return to operating system               */
  365. /*--------------------------------------------------------------------*/
  366.  
  367. static void Terminate( const int rc)
  368. {
  369.    if (tempname != NULL)         /* Did temporary file get named?    */
  370.    {
  371.       if (datain != stdin)       /* Non-standard input?              */
  372.         fclose(stdin);           /* Yes --> Close it                 */
  373.       remove(tempname);          /* Purge temporary file, if exists  */
  374.    } /* if */
  375.  
  376.    if (logfile != stdout )       /* Was the disk logfile open?       */
  377.    {                             /* Yes --> Close it                 */
  378.       if ( logfile != NULL )     /* Was it REALLY open?              */
  379.          fclose(logfile);        /* Yes --> Close it                 */
  380.       logfile = stdout;          /* Restore for late breaking msgs   */
  381.    } /* if */
  382.  
  383.    exit( rc );                   /* Return to operating systems      */
  384. }  /* Terminate */
  385.  
  386. /*--------------------------------------------------------------------*/
  387. /*    P a r s e F r o m                                               */
  388. /*                                                                    */
  389. /*    Read the from address of incoming data from UUCP                */
  390. /*--------------------------------------------------------------------*/
  391.  
  392. static void ParseFrom()
  393. {
  394.    static char from[] = "From ";
  395.    static char remote[] = "remote from ";
  396.    static int  remotelen = sizeof remote - 1;
  397.    static int  fromlen = sizeof from - 1;
  398.    char *token;
  399.    char buf[BUFSIZ];
  400.    boolean hit;
  401.  
  402. /*--------------------------------------------------------------------*/
  403. /*                Use UUXQT Information, if available                 */
  404. /*--------------------------------------------------------------------*/
  405.  
  406.    token = getenv( UU_MACHINE );
  407.    if ( token == NULL )
  408.       *fromnode = '\0';
  409.    else
  410.       strcpy( fromnode, token );
  411.  
  412.    fgets(buf, BUFSIZ , datain);
  413.    hit = equaln(buf, from, fromlen );
  414.  
  415.    if (hit)
  416.    {
  417.       strcpy(fromuser, strtok( &buf[ fromlen ], " ")  );
  418.  
  419.       if ( *fromnode == '\0')
  420.       {
  421.          token = strtok( NULL, "\n");
  422.          while ( *token != '\0')
  423.          {
  424.             if equaln(token, remote, remotelen)
  425.                break;
  426.             else
  427.                token++;
  428.          } /* while */
  429.          strcpy(fromnode ,
  430.                 (*token == '\0') ? nodename : &token[ remotelen ] );
  431.       } /* if ( *fromnode != '\0') */
  432.  
  433.    } /* if */
  434.    else {
  435.       if ( *fromnode == '\0')
  436.          strcpy(fromnode, nodename );
  437.       strcpy(fromuser, "/dev/null");
  438.    } /* else */
  439.  
  440. /*--------------------------------------------------------------------*/
  441. /*       Generate required "From " and "Received" header lines        */
  442. /*--------------------------------------------------------------------*/
  443.  
  444.    fprintf(dataout,"%-10s from %s by %s (%s %s) with UUCP;\n%-10s %s\n",
  445.             "Received:", fromnode, domain, compilep, compilev,
  446.             " ", now);
  447.  
  448. /*--------------------------------------------------------------------*/
  449. /*    If what we read wasn't a From line, write into the new file     */
  450. /*--------------------------------------------------------------------*/
  451.  
  452.    if (!hit)
  453.    {
  454.       fputs(buf, dataout);
  455.       if (ferror(dataout))
  456.       {
  457.          printerr(tempname);
  458.          Terminate(3);
  459.       } /* if */
  460.    } /* if */
  461.  
  462. }  /* ParseFrom */
  463.  
  464.  
  465. /*--------------------------------------------------------------------*/
  466. /*    P a r s e 8 2 2                                                 */
  467. /*                                                                    */
  468. /*    Parse an RFC-822 header generated by that esteemed mail user    */
  469. /*    agent, UUPC/extended's MAIL.                                    */
  470. /*                                                                    */
  471. /*    Note that we parse the header in the format we KNOW that UUPC   */
  472. /*    generated it in:  "To:", "Cc:", "Bcc:", optionally prefixed     */
  473. /*    by "Resent-".  We also know that mail comes in one address      */
  474. /*    per line, and that the Resent- headers, if any, precede the     */
  475. /*    original headers.                                               */
  476. /*--------------------------------------------------------------------*/
  477.  
  478. static char **Parse822( boolean *header,
  479.                         size_t *count)
  480. {
  481.  
  482. /*--------------------------------------------------------------------*/
  483. /*  Define the headers we will be examining and variables for their   */
  484. /*                              lengths                               */
  485. /*--------------------------------------------------------------------*/
  486.  
  487.    static char *to     = "Resent-To:";
  488.    static char *cc     = "Resent-Cc:";
  489.    static char *bcc    = "Resent-Bcc:";
  490.    static char *resent = "Resent-";
  491.    static char *from   = "Resent-From:";
  492.  
  493.    size_t tolen;
  494.    size_t cclen;
  495.    size_t bcclen;
  496.    size_t resentlen =  strlen(resent);
  497.    size_t offset = resentlen; /* Subscript for examining headers,
  498.                                  which allows us to ignore Resent-   */
  499.    size_t fromlen =  strlen( &from[offset] );
  500.    size_t allocated = 5;      /* Reasonable first size for address   */
  501.                               /* Note: MUST BE AT LEAST 2 because we
  502.                                        add 50% below!                */
  503.    boolean blind = FALSE;
  504.  
  505.    char **addrlist = calloc( sizeof *addrlist , allocated);
  506.    char buf[BUFSIZ];          /* Input buffer for reading header     */
  507.    char address[MAXADDR];     /* Buffer for parsed address           */
  508.    char path[MAXADDR];
  509.    char *token;               /* For parsing line in buf             */
  510.    struct HostTable *hostp;
  511.  
  512. /*--------------------------------------------------------------------*/
  513. /*                          Begin processing                          */
  514. /*--------------------------------------------------------------------*/
  515.  
  516.    *count = 0;                /* No addresses discovered yet         */
  517.    checkref(addrlist);        /* Verify we had room for the list     */
  518.  
  519.    fprintf(dataout,"%-10s by %s (%s %s);\n%-10s %s\n",
  520.               "Received:",domain,compilep, compilev,
  521.               " ", now );
  522.  
  523. /*--------------------------------------------------------------------*/
  524. /*                        Find the From: line                         */
  525. /*--------------------------------------------------------------------*/
  526.  
  527.    do {
  528.       if (fgets( buf, BUFSIZ, datain) == NULL)  /* End of file?      */
  529.          return NULL;         /* Yes --> Very bad, report error      */
  530.       fputs(buf, dataout );
  531.       if (*buf == '\n')       /* End of the header?                  */
  532.          return NULL;         /* Yes --> Very bad, report error      */
  533.       else if (equalni(resent, buf, resentlen))
  534.       {
  535.          offset = 0;
  536.          fromlen = strlen(&from[offset]);
  537.       } /* if */
  538.       else if (equalni(received, buf, receivedlen))
  539.          hops++;
  540.    } while (!equalni(&from[offset], buf, fromlen));
  541.  
  542.    strtok( buf , WHITESPACE);    /* Drop the leading token           */
  543.    token = strtok( NULL, "\n");  /* Get the token with From: addr    */
  544.    ExtractAddress( address, token, FALSE );
  545.                                  /* Get the From: address itself     */
  546.    user_at_node(address, path, fromnode, fromuser);
  547.                                  /* Separate portions of the address */
  548.  
  549. /*--------------------------------------------------------------------*/
  550. /*               Generate a Sender: line if we need it                */
  551. /*--------------------------------------------------------------------*/
  552.  
  553.    if (equal(fromnode,HostAlias(fdomain)))   /* Same as hidden site? */
  554.       strcpy(fromnode, nodename);/* Yes --> Declare as local system  */
  555.  
  556.    hostp = checkname( fromnode );   /* Look up real system name      */
  557.  
  558.    if (!equal(fromuser,mailbox) ||
  559.        (hostp == BADHOST) || (hostp->hstatus != localhost))
  560.    {
  561.       sprintf(buf, "%s <%s@%s>", name, mailbox, fdomain );
  562.       PutHead("Sender:", buf, dataout , offset == 0 );
  563.    } /* if */
  564.  
  565. /*--------------------------------------------------------------------*/
  566. /*                       Generate a message-id                        */
  567. /*--------------------------------------------------------------------*/
  568.  
  569.    sprintf(buf, "<%lx.%s@%s>", time( NULL ) , nodename, domain);
  570.    PutHead("Message-ID:", buf, dataout , offset == 0 );
  571.    PutHead(NULL, NULL, dataout , FALSE );
  572.  
  573. /*--------------------------------------------------------------------*/
  574. /*                 Locate the To: or Resent-To: line                  */
  575. /*--------------------------------------------------------------------*/
  576.  
  577.    tolen =    strlen( &to[offset] );
  578.  
  579.    do {
  580.       if (fgets( buf, BUFSIZ, datain ) == NULL)  /* End of file?     */
  581.          return NULL;         /* Yes --> Very bad, report error      */
  582.       fputs(buf, dataout );
  583.       if (*buf == '\n')       /* End of the header?                  */
  584.          return NULL;         /* Yes --> Very bad, report error      */
  585.       else if (equalni(received, buf, receivedlen))
  586.          hops++;
  587.    } while ( !equalni(&to[offset] , buf , tolen ));
  588.  
  589.    token = strpbrk( buf ," \t");
  590.  
  591. /*--------------------------------------------------------------------*/
  592. /*                Proccess the rest of the addressees                 */
  593. /*--------------------------------------------------------------------*/
  594.  
  595.    cclen =    strlen( &cc[offset] );
  596.    bcclen =   strlen( &bcc[offset] );
  597.  
  598.    do {
  599.       if (allocated == (*count+1))  /* Do we have room for addr?     */
  600.       {
  601.          allocated += allocated / 2;   /* Choose larger array size   */
  602.          addrlist = realloc( addrlist ,
  603.                              allocated * sizeof( *addrlist ));
  604.          checkref(addrlist);  /* Verify the allocation worked        */
  605.       } /* if */
  606.  
  607.       ExtractAddress( address, token, FALSE );  /* Get address itself*/
  608.       if (!strlen(address))
  609.       {
  610.          printmsg(0,"Could not locate expected address in header");
  611.          *count = 0;
  612.          return NULL;
  613.       } /* if */
  614.       else {
  615.          addrlist[*count] = strdup( address );
  616.                               /* Save permanent copy of address      */
  617.          checkref( addrlist[*count] ); /* Verify strdup worked       */
  618.          printmsg(4,"address[%d]= \"%s\"",*count, address);
  619.          *count += 1;         /* Flag we got the address             */
  620.       } /* else */
  621.  
  622.       if (fgets( buf, BUFSIZ, datain ) == NULL) /* End of file?      */
  623.          token = NULL;        /* Yes --> Odd, but no major problem   */
  624.       else if (*buf == '\n')  /* End of the header?                  */
  625.       {
  626.          token = NULL;        /* Yes --> Exit loop                   */
  627.          *header = FALSE;     /* Report to caller the header is done */
  628.          blind = FALSE;       /* Denote not a blind header           */
  629.       }
  630.       else if (isspace(*buf)) /* Another address?                    */
  631.          token = buf;         /* Yes --> Write it out                */
  632.       else {                  /* No --> Determine what next header is*/
  633.          blind = FALSE;       /* Assume not a blind header           */
  634.          if (equalni(&cc[offset], buf, cclen))   /* Cc: header?       */
  635.             token = strpbrk(buf," \t");
  636.          else if (equalni(&bcc[offset], buf, bcclen))  /* Bcc: header?*/
  637.          {
  638.             token = strpbrk(buf ," \t");
  639.             blind = TRUE;
  640.          } /* if */
  641.          else                 /* Unsupported header, exit loop       */
  642.             token = NULL;
  643.       } /* else */
  644.       if ( ! blind )
  645.          fputs(buf, dataout );
  646.    } while (token != NULL );
  647.  
  648.    return addrlist;
  649.  
  650. } /* Parse822 */
  651.  
  652. /*--------------------------------------------------------------------*/
  653. /*    C o p y T e m p                                                 */
  654. /*                                                                    */
  655. /*    Copy the un-parsed parts of a message into the holding file     */
  656. /*--------------------------------------------------------------------*/
  657.  
  658. static boolean CopyTemp( void )
  659. {
  660.    boolean header = TRUE;
  661.    char buf[BUFSIZ];
  662.    boolean newline = TRUE;
  663.  
  664.    while (fgets(buf, BUFSIZ, datain) != NULL)
  665.    {
  666.       if (header)
  667.       {
  668.          if (*buf == '\n')
  669.             header = FALSE;
  670.          else if (equalni(received, buf, receivedlen))
  671.             hops++;
  672.       }
  673.  
  674.       newline = buf[ strlen( buf ) - 1 ] == '\n';
  675.  
  676.       if (fputs(buf, dataout) == EOF)  /* I/O error?                 */
  677.       {
  678.          printerr(tempname);
  679.          printmsg(0,"I/O error on \"%s\"", tempname);
  680.          fclose(dataout);
  681.          return FALSE;
  682.       } /* if */
  683.    } /* while */
  684.  
  685.    if (ferror(datain))        /* Clean end of file on input?         */
  686.    {
  687.       printerr(namein);
  688.       Terminate(3);
  689.    }
  690.  
  691.    if ( !newline )            /* Is the file terminated properly?    */
  692.    {
  693.       printmsg(0, "rmail: Improperly formed message, adding final newline!");
  694.       fputc( '\n', dataout );
  695.    }
  696.  
  697.    return header;
  698. }  /* CopyTemp */
  699.  
  700. /*--------------------------------------------------------------------*/
  701. /*    D a e m o n M a i l                                             */
  702. /*                                                                    */
  703. /*    Send text in a mailbag file to address(es) specified by address */
  704. /*--------------------------------------------------------------------*/
  705.  
  706. static boolean DaemonMail( const char *subject,
  707.                           char **address,
  708.                           int count )
  709. {
  710.    char buf[BUFSIZ];
  711.    char *logname;
  712.    char *token;
  713.    char *moi = NULL;
  714.    struct UserTable *userp;
  715.    char *header = "To:";
  716.    char *cc     = "Cc:";
  717.    boolean print = TRUE;
  718.  
  719. /*--------------------------------------------------------------------*/
  720. /*                         Validate the input                         */
  721. /*--------------------------------------------------------------------*/
  722.  
  723.    if ( count == 0 )
  724.    {
  725.       printmsg(0,"rmail: No addresseses to deliver to!");
  726.       return FALSE;
  727.    }
  728.  
  729. /*--------------------------------------------------------------------*/
  730. /*                       Determine our user id                        */
  731. /*--------------------------------------------------------------------*/
  732.  
  733.    logname = getenv( LOGNAME );
  734.    if ( logname == NULL )
  735.       logname = mailbox;
  736.  
  737. /*--------------------------------------------------------------------*/
  738. /*              Get the name of the user, or make one up              */
  739. /*--------------------------------------------------------------------*/
  740.  
  741.    userp = checkuser(logname);   /* Locate user id in host table     */
  742.  
  743.    if ( (userp != BADUSER) && (userp->realname != NULL) )
  744.       moi = userp->realname;
  745.    else if ( equali(logname, postmaster) || equali(logname, POSTMASTER))
  746.       moi = "Postmaster";
  747.    else if ( equali( logname, "uucp" ))
  748.       moi = "Unix to Unix Copy";
  749.    else
  750.       moi = logname;          /* Dummy to ease formatting From: line  */
  751.  
  752. /*--------------------------------------------------------------------*/
  753. /*    Add the boilerplate the front:                                  */
  754. /*                                                                    */
  755. /*       Date, From, Organization, and Reply-To                       */
  756. /*--------------------------------------------------------------------*/
  757.  
  758.    fprintf(dataout,"%-10s by %s (%s %s);\n%-10s %s\n",
  759.               "Received:",domain,compilep, compilev,
  760.               " ", now );
  761.  
  762. /*--------------------------------------------------------------------*/
  763. /*                       Generate a message-id                        */
  764. /*--------------------------------------------------------------------*/
  765.  
  766.    sprintf(buf, "<%lx.%s@%s>", time( NULL ) , nodename, domain);
  767.    PutHead("Message-ID:", buf, dataout , FALSE );
  768.    PutHead(NULL, NULL, dataout , FALSE );
  769.  
  770.    PutHead("Date:", arpadate() , dataout, FALSE);
  771.  
  772.    if (bflag[F_BANG])
  773.       sprintf(buf, "(%s) %s!%s", moi, nodename, logname );
  774.    else
  775.       sprintf(buf, "\"%s\" <%s@%s>", moi, logname , fdomain );
  776.  
  777.    PutHead("From:", buf, dataout, FALSE );
  778.  
  779.    if (organization != NULL )
  780.       PutHead("Organization:", organization, dataout, FALSE);
  781.  
  782. /*--------------------------------------------------------------------*/
  783. /*                      Write the address out                         */
  784. /*--------------------------------------------------------------------*/
  785.  
  786.    while( (count-- > 0) && print )
  787.    {
  788.       token = *address++;
  789.       if ( *token == '-')  /* Option flag?                        */
  790.       {
  791.          if (token[1] == 'c')
  792.          {
  793.             header = cc;
  794.             cc = "";
  795.          }
  796.          else if (token[1] == 'b')
  797.             print = FALSE;
  798.          else
  799.             printmsg(0,"rmail: Invalid flag \"%s\" ignored!", token);
  800.       } /* if ( token == '-') */
  801.       else if ( print )
  802.       {
  803.          if (strpbrk(token,"!@") == nil(char))
  804.          {
  805.             if (bflag[F_BANG])
  806.                sprintf(buf, "%s!%s", nodename, token );
  807.             else
  808.                sprintf(buf, "%s@%s", token , fdomain );
  809.             token = buf;
  810.          }
  811.  
  812.          PutHead(header , token, dataout, FALSE);
  813.          header = "";         /* Continue same field by default      */
  814.       }
  815.    } /* while( (count-- > 0) && print ) */
  816.  
  817. /*--------------------------------------------------------------------*/
  818. /*                     Handle the subject, if any                     */
  819. /*--------------------------------------------------------------------*/
  820.  
  821.    if (subject != NULL)
  822.       PutHead("Subject:", subject, dataout, FALSE);
  823.  
  824.    PutHead(NULL, "", dataout, FALSE);  /* Terminate the header line   */
  825.    PutHead(NULL, "", dataout, FALSE);  /* Terminate the header file   */
  826.  
  827. /*--------------------------------------------------------------------*/
  828. /*                          Return to caller                          */
  829. /*--------------------------------------------------------------------*/
  830.  
  831.    strcpy(fromuser, logname); /* Define user for UUCP From line      */
  832.    strcpy(fromnode, nodename);/* Declare as local system             */
  833.    return TRUE;
  834.  
  835. } /*DaemonMail*/
  836.  
  837. /*--------------------------------------------------------------------*/
  838. /*    P u t H e a d                                                   */
  839. /*                                                                    */
  840. /*    Write one line of an RFC-822 header                             */
  841. /*--------------------------------------------------------------------*/
  842.  
  843.  static void PutHead( const char *label,
  844.                       const char *operand,
  845.                       FILE *stream,
  846.                       const boolean resent)
  847.  {
  848.    static boolean terminate = TRUE;
  849.  
  850.    if (label == NULL )        /* Terminate call?                     */
  851.    {                          /* Yes --> Reset Flag and return       */
  852.       fputc('\n', stream);    /* Terminate the current line          */
  853.       terminate = TRUE;
  854.       return;
  855.    } /* if */
  856.  
  857.    if (strlen(label))         /* First line of a header?             */
  858.    {
  859.       if (!terminate)         /* Terminate previous line?            */
  860.          fputc('\n', stream);
  861.  
  862.       if (resent)
  863.          fprintf(stream,"Resent-%s %s",label, operand);
  864.       else
  865.          fprintf(stream,"%-10s %s",label, operand);
  866.       terminate = FALSE;          /* Flag that we did not end file   */
  867.    } /* if */
  868.    else                       /* Continuing line                     */
  869.       fprintf(stream,",\n%-10s %s",label, operand);
  870.  } /* PutHead */
  871.